﻿using System;
using System.Collections;
using System.Collections.Generic;
using Gameplay.PVE;
using Gameplay.PVE.Entity;
using UnityEngine;

public enum E_Node_Type
{
    //可以走的地方
    Walk,
    
    //阻挡点
    Stop,
}

/// <summary>
/// A星格子
/// </summary>
public class AStarNode:IComparable<AStarNode>
{
    //坐标
    public int x;
    public int y;

    //寻路消耗
    public float f;

    //离起点的距离
    public float g;

    //离终点的距离
    public float h;

    public E_Node_Type type;
    
    public AStarNode father;

    private Dictionary<int, int> dynamicBlocks = new Dictionary<int, int>();

    private Dictionary<int, int> staticBlocks = new Dictionary<int, int>();

    public Dictionary<int, float> blockDistance = new Dictionary<int, float>();
    
    public HashSet<int> units = new HashSet<int>();
    
    public float maxClearDistance;
    
    private Dictionary<AStarBlockType, float> maxClearDistances = new Dictionary<AStarBlockType, float>();

    public bool isValid;

    private bool lastValidType;

    public bool isInCloseList = false;

    public bool isInOpenList = false;

    //用于判断当前点被筛选出来时是否是周围都没有阻挡的
    public bool isNoneBlock = false;
    
    public void RemoveUnit(int id)
    {
        units.Remove(id);
    }

    public void AddUnit(int id)
    {
        units.Add(id);
    }
    
    public void CheckNeedNotifyRepath()
    {
        var validType = IsClear(2);
        if (validType != lastValidType)
        {
            foreach (var id in units)
            {
                var unit = UnitManager.Instance.GetUnit(id);
                if (unit != null && !unit.Data.isDead)
                {
                    unit.Transmit(ETransmitType.RePath);
                }
            }
            lastValidType = validType;
        }
    }
    
    public void ClearBlocks()
    {
        dynamicBlocks.Clear();
        type = E_Node_Type.Walk;
        blockDistance.Clear();
        maxClearDistance = 100;
        maxClearDistances.Clear();
        foreach (var item in staticBlocks)
        {
            UpdateClearArea(item.Key, 0);
        }
        isValid = true;
    }

    public void AddBlock(int id,bool isStatic = false,AStarBlockType blockType = AStarBlockType.Ground)
    {
        if (isStatic)
        {
            if (!staticBlocks.ContainsKey(id))
            {
                staticBlocks.Add(id,1);
            }
            UpdateClearArea(id,0,blockType);
        }
        else
        {
            //if (!dynamicBlocks.ContainsKey(id))
            {
                dynamicBlocks[id] = 1;
            }
            //UpdateClearArea(id,0);
        }
        type = E_Node_Type.Stop;
    }

    public void UpdateClearArea(int id,float distance,AStarBlockType blockType = AStarBlockType.Ground)
    {
        blockDistance[id] = distance;
        if (maxClearDistance > distance)
        {
            maxClearDistance = distance;
        }

        if (!maxClearDistances.TryGetValue(blockType, out var d) || d > distance)
        {
            maxClearDistances[blockType] = distance;
        }
    }

    public bool RemoveBlock(int id,bool isStatic = false,AStarBlockType blockType = AStarBlockType.Ground)
    {
        bool haveBlock = false;
        if (isStatic)
        {
            haveBlock = staticBlocks.Remove(id);
            haveBlock = blockDistance.Remove(id) || haveBlock;
            maxClearDistance = 100;
            foreach (var item in blockDistance)
            {
                if (maxClearDistance > item.Value)
                {
                    maxClearDistance = item.Value;
                }
            }
        }
        else
        {
            haveBlock = dynamicBlocks.Remove(id);
        }
        type = staticBlocks.Count == 0 && dynamicBlocks.Count == 0 ? E_Node_Type.Walk : E_Node_Type.Stop;
        return haveBlock;
    }

    public void RemoveAroundBlock(int id)
    {
        if (!blockDistance.TryGetValue(id, out var originDistance))
        {
            return;
        }
        blockDistance.Remove(id);
        if (maxClearDistance == originDistance)
        {
            maxClearDistance = 100;
            foreach (var item in blockDistance)
            {
                if (maxClearDistance > item.Value)
                {
                    maxClearDistance = item.Value;
                }
            }

            maxClearDistances.Clear();
        }
    }

    public bool IsClear(float distance)
    {
        return maxClearDistance > distance && type == E_Node_Type.Walk;
    }

    public bool IsClear(float distance, AStarBlockType blockType)
    {
        if (maxClearDistances.TryGetValue(blockType, out var d))
        {
            return d > distance;
        }

        return IsClear(distance);
    }

    public void ClearStatic()
    {
        staticBlocks.Clear();
    }
    
    public AStarNode(int x,int y,E_Node_Type type)
    {
        this.x = x;
        this.y = y;
        this.type = type;
        maxClearDistance = 100;
    }

    public int CompareTo(AStarNode obj)
    {
        if (f > obj.f)
            return 1;
        else if (f == obj.f)
            return 1;
        else
            return -1;
    }
}



